package com.lyf.common.aspect;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * @date 2019/2/12
 * @time 14:03
 * @discription
 **/
@Aspect
@Component
@Slf4j
public class WebLogAspect {

    final ObjectMapper mapper = new ObjectMapper();

    @Pointcut("execution(public * com.lyf..*.controller..*.*(..))")
    public void webLogAccount() {
    }

    @Pointcut("webLogAccount()")
    public void webLog() {
    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();


        // 打印请求相关参数
        log.info("========================================== Start ==========================================");
        // 打印请求 url
        log.info("Request Info: [ IP:{}, HTTP Method:{}，URL: {}]", request.getRemoteAddr(),
                request.getMethod(), request.getRequestURL().toString());

        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印header请求
        String headerValue = getHeaderValue(request);
        log.info("Request header info   : {}", headerValue);

        // 打印请求入参
        Map<String, Object> map = new HashMap<>();
        //参数value
        Object[] args = joinPoint.getArgs();
        // 参数key
        String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof MultipartFile
                    || args[i] instanceof HttpServletRequest
                    || args[i] instanceof HttpServletResponse) {
                continue;
            }
            map.put(argNames[i], args[i]);
        }

        try {
            String ret = mapper.writeValueAsString(map);
            log.info("Request Args   : {}", ret);
        } catch (JsonProcessingException e) {
            log.error("JsonProcessingException", e);
        }

    }

    /**
     * 在切点之后织入
     *
     * @throws Throwable
     */
    @After("webLog()")
    public void doAfter() throws Throwable {
        log.info("=========================================== End ===========================================");
        // 每个请求之间空一行
        log.info("");
    }

    /**
     * 环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();

        // 打印出参 header
        log.info("Response header  : {}", getHeaderValue(response));

        // 打印出参 body
//        if (result instanceof CommonResult) {
//            log.info("Response Args  : {}", new Gson().toJson(result));
//        }
        // 执行耗时
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }

    private String getHeaderValue(HttpServletRequest request) {

        StringBuilder str = new StringBuilder();
        String curHeaderName = "";
        Enumeration<String> keys = request.getHeaderNames();
        while (keys.hasMoreElements()) {
            curHeaderName = keys.nextElement();
            if (curHeaderName.contains("accept-charset")) {
                continue;
            }
            str.append(curHeaderName + "=");
            str.append(request.getHeader(curHeaderName) + ", ");
        }
        return str.toString();
    }

    private String getHeaderValue(HttpServletResponse response) {

        StringBuilder str = new StringBuilder();
        String curHeaderName = "";
        Iterator<String> keys = response.getHeaderNames().iterator();
        while (keys.hasNext()) {
            curHeaderName = keys.next();
            if (curHeaderName.contains("accept-charset")) {
                continue;
            }
            str.append(curHeaderName + "=");
            str.append(response.getHeader(curHeaderName) + ", ");
        }
        return str.toString();
    }
}
